Skip to content

feat: add file deletion feature to menu actions#78

Draft
nyatinte wants to merge 1 commit intomainfrom
claude/implement-rm-feature-011CUutvDYsuN3KWK8GLwqdh
Draft

feat: add file deletion feature to menu actions#78
nyatinte wants to merge 1 commit intomainfrom
claude/implement-rm-feature-011CUutvDYsuN3KWK8GLwqdh

Conversation

@nyatinte
Copy link
Owner

@nyatinte nyatinte commented Nov 8, 2025

Implements file deletion functionality with confirmation dialog.
Users can now delete Claude configuration files directly from the
interactive menu using the 'x' key shortcut.

Changes:

  • Add delete file action to menu with 'x' key binding
  • Require confirmation before deleting files
  • Update README with new keyboard shortcut
  • Add tests for delete functionality
  • Add TypeScript as dev dependency for build compatibility

Resolves user request to incorporate file deletion feature
to cleanup redundant tools/agents alongside existing edit/view options.

Summary by CodeRabbit

  • New Features

    • Added keyboard shortcut (x) to delete files with confirmation in the menu.
  • Chores

    • Updated TypeScript to version 5.9.3.

Implements file deletion functionality with confirmation dialog.
Users can now delete Claude configuration files directly from the
interactive menu using the 'x' key shortcut.

Changes:
- Add delete file action to menu with 'x' key binding
- Require confirmation before deleting files
- Update README with new keyboard shortcut
- Add tests for delete functionality
- Add TypeScript as dev dependency for build compatibility

Resolves user request to incorporate file deletion feature
to cleanup redundant tools/agents alongside existing edit/view options.
@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

Walkthrough

A new "Delete file" action is added to the application menu with confirmation workflow. The action is documented in README, implemented in the menu hook with fs/promises unlink operation, tested with comprehensive test cases, and TypeScript dependency is updated.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added keyboard shortcut documentation for the new Delete file action (x - Delete file with confirmation)
Dependencies
package.json
Updated TypeScript to version ^5.9.3 in devDependencies
Tests
src/components/FileList/MenuActions.test.tsx
Extended test suite to verify the new Delete File action is present, properly positioned after Open File action, and included in rendered output; total actions increased from 6 to 7
Implementation
src/components/FileList/MenuActions/hooks/useMenu.ts
Added Delete File action that loads fs/promises, defines performDelete function to unlink the file, sets confirmation message, enables confirmation UI, and queues the deletion for execution after user confirms

Sequence Diagram

sequenceDiagram
    actor User
    participant Menu
    participant Handler
    participant Confirmation
    participant fs as fs/promises

    User->>Menu: Select Delete File (x)
    Menu->>Handler: Trigger delete action
    Handler->>Handler: Load fs/promises
    Handler->>Confirmation: Set confirmation message
    Handler->>Confirmation: Enable confirmation UI
    Handler->>Handler: Queue performDelete<br/>Return empty string
    Confirmation->>User: Show confirmation dialog
    
    alt User Confirms
        User->>Confirmation: Confirm deletion
        Confirmation->>fs: unlink(file path)
        fs->>fs: Delete file
        fs-->>Handler: Success
        Handler-->>User: Display success message
    else User Cancels
        User->>Confirmation: Cancel
        Confirmation-->>User: Deletion cancelled
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • The addition follows an established pattern for confirmation-based actions
  • Test updates are straightforward index and expectation assertions
  • New delete logic is minimal and uses standard Node.js fs/promises API
  • Changes are localized to menu actions without impacting other systems

Possibly related PRs

Poem

🐰 A file now deleted with care,
Confirmation asked with a prayer,
No accidents here, just peace of mind,
The trash bin awaits, confirmation designed!
x marks the spot—twice! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add file deletion feature to menu actions' directly and clearly describes the main change in the changeset: adding a file deletion capability to the menu. It aligns with the PR's primary objective and is reflected in all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/implement-rm-feature-011CUutvDYsuN3KWK8GLwqdh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/components/FileList/MenuActions/hooks/useMenu.ts (2)

238-241: Enhance error handling for common deletion failure scenarios.

The generic error handling may not provide clear guidance for common failure cases like permission errors or attempting to delete an already-deleted file.

Consider adding specific error handling:

 const performDelete = async () => {
-  await fs.unlink(file.path);
+  try {
+    await fs.unlink(file.path);
+  } catch (error) {
+    if (
+      error &&
+      typeof error === 'object' &&
+      'code' in error
+    ) {
+      if (error.code === 'ENOENT') {
+        throw new Error('File no longer exists (may have been deleted externally)');
+      }
+      if (error.code === 'EPERM' || error.code === 'EACCES') {
+        throw new Error('Permission denied: Cannot delete this file');
+      }
+    }
+    throw error;
+  }
   return `✅ File deleted: ${basename(file.path)}`;
 };

244-246: Consider shorter confirmation message for better UX.

The confirmation message is quite long. A more concise version would improve readability while maintaining clarity.

 setConfirmMessage(
-  `Are you sure you want to delete "${basename(file.path)}"? This action cannot be undone.`,
+  `Delete "${basename(file.path)}"? This cannot be undone.`,
 );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c218a5f and eb19053.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • package.json (1 hunks)
  • src/components/FileList/MenuActions.test.tsx (5 hunks)
  • src/components/FileList/MenuActions/hooks/useMenu.ts (1 hunks)
🔇 Additional comments (3)
README.md (1)

179-179: LGTM!

The documentation clearly describes the new delete functionality and appropriately notes that confirmation is required. The placement at the end of the keyboard shortcuts list is logical for a destructive action.

src/components/FileList/MenuActions.test.tsx (1)

57-57: Test coverage for Delete File display and ordering looks good.

The tests properly verify that the Delete File action appears in the UI with the correct label, key binding, and ordering (after Open File).

Also applies to: 161-168, 230-230, 238-238, 385-385, 418-418

package.json (1)

75-75: TypeScript version 5.9.3 is valid, current, and has no known vulnerabilities.

The verification confirms that 5.9.3 is a legitimate release and is the latest stable version available on npm. No security advisories were found. The dependency in package.json is appropriate and requires no changes.

expect(lastFrame()).toContain('[D] Copy to Current Directory');
expect(lastFrame()).toContain('[E] Edit File');
expect(lastFrame()).toContain('[O] Open File');
expect(lastFrame()).toContain('[X] Delete File');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add functional tests for the delete action and confirmation flow.

The current tests only verify UI rendering. Essential tests are missing for the core delete functionality, confirmation dialog interaction, and error handling.

Consider adding these test cases:

  1. Confirmation dialog display test: Verify that pressing 'x' triggers the confirmation dialog
  2. Successful deletion test: Verify file is deleted after confirming
  3. Deletion cancellation test: Verify file is NOT deleted after canceling
  4. Error handling tests: Test permission errors and file-not-found scenarios
  5. Post-deletion behavior: Verify the menu closes or refreshes after deletion

Example test structure:

test('delete file shows confirmation dialog', async () => {
  await withCachedReadOnlyFixture(
    {
      'test-project': {
        'test.md': '# Test',
      },
    },
    async (fixture) => {
      const file = createFileInfo(
        fixture.path,
        'test-project/test.md',
        'project-memory',
      );
      const onClose = vi.fn();

      const { stdin, lastFrame } = render(
        <MenuActions file={file} onClose={onClose} />,
      );

      // Trigger delete action
      stdin.write('x');

      await waitFor(() => {
        const output = lastFrame();
        if (!output || !output.includes('Delete "test.md"?')) {
          throw new Error('Confirmation dialog not shown');
        }
      }, 100);

      // Verify confirmation message
      expect(lastFrame()).toContain('Delete "test.md"?');
      expect(lastFrame()).toContain('cannot be undone');
    },
  );
});

test('delete file removes file after confirmation', async () => {
  // Test actual file deletion after Y confirmation
});

test('delete file cancels when user declines', async () => {
  // Test file is NOT deleted after N/Esc
});

Would you like me to generate complete test implementations for the delete functionality?

🤖 Prompt for AI Agents
In src/components/FileList/MenuActions.test.tsx around line 57, the tests only
assert UI rendering and lack functional coverage for the delete action and
confirmation flow; add tests that (1) press 'x' to open the confirmation dialog
and assert lastFrame() contains 'Delete "filename"?' and 'cannot be undone', (2)
simulate confirming deletion (write 'y' or Enter) and verify the file is removed
from the fixture (use withCachedReadOnlyFixture and createFileInfo) and any
expected UI/menu refresh or onClose is called, (3) simulate cancelling deletion
('n' or Escape) and assert the file still exists and menu remains/open state is
unchanged, (4) add error-handling tests by mocking the delete operation to throw
permission or not-found errors and assert appropriate error messages are shown,
and (5) assert post-deletion behavior such as the menu closing or refresh by
checking onClose was called or lastFrame() no longer shows the deleted file; for
all tests use render to obtain stdin/lastFrame, waitFor to poll UI changes, and
inspect the fixture filesystem or mocked delete calls to confirm side effects.

Comment on lines +230 to +253
{
key: 'x',
label: 'Delete File',
description: 'Delete file (requires confirmation)',
action: async () => {
const fs = await import('node:fs/promises');

// The actual deletion operation
const performDelete = async () => {
await fs.unlink(file.path);
return `✅ File deleted: ${basename(file.path)}`;
};

// Always require confirmation for deletion
setConfirmMessage(
`Are you sure you want to delete "${basename(file.path)}"? This action cannot be undone.`,
);
setIsConfirming(true);
setPendingAction(() => performDelete);

// Return early, action will be executed after confirmation
return '';
},
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Menu remains open after file deletion, showing a non-existent file.

After successfully deleting a file, the menu remains open and continues to display the now-deleted file. This creates a confusing UX where users can attempt further actions on a file that no longer exists, leading to ENOENT errors.

Consider one of these solutions:

Solution 1 (recommended): Close the menu immediately after successful deletion

Modify the performDelete function to trigger menu closure:

 const performDelete = async () => {
   await fs.unlink(file.path);
+  onClose(); // Close menu immediately after deletion
   return `✅ File deleted: ${basename(file.path)}`;
 };

Solution 2: Add a callback to refresh the parent file list

If the parent component maintains a file list that should be refreshed:

 type UseMenuProps = {
   readonly file: ClaudeFileInfo;
   readonly onClose: () => void;
+  readonly onFileDeleted?: (path: string) => void;
 };

Then call it after deletion:

 const performDelete = async () => {
   await fs.unlink(file.path);
+  onFileDeleted?.(file.path);
+  onClose();
   return `✅ File deleted: ${basename(file.path)}`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
key: 'x',
label: 'Delete File',
description: 'Delete file (requires confirmation)',
action: async () => {
const fs = await import('node:fs/promises');
// The actual deletion operation
const performDelete = async () => {
await fs.unlink(file.path);
return `✅ File deleted: ${basename(file.path)}`;
};
// Always require confirmation for deletion
setConfirmMessage(
`Are you sure you want to delete "${basename(file.path)}"? This action cannot be undone.`,
);
setIsConfirming(true);
setPendingAction(() => performDelete);
// Return early, action will be executed after confirmation
return '';
},
},
{
key: 'x',
label: 'Delete File',
description: 'Delete file (requires confirmation)',
action: async () => {
const fs = await import('node:fs/promises');
// The actual deletion operation
const performDelete = async () => {
await fs.unlink(file.path);
onClose(); // Close menu immediately after deletion
return `✅ File deleted: ${basename(file.path)}`;
};
// Always require confirmation for deletion
setConfirmMessage(
`Are you sure you want to delete "${basename(file.path)}"? This action cannot be undone.`,
);
setIsConfirming(true);
setPendingAction(() => performDelete);
// Return early, action will be executed after confirmation
return '';
},
},

@nyatinte nyatinte marked this pull request as draft November 8, 2025 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants